import { CodeHighlightDemos } from '@docs/demos';
import { Layout } from '@/layout';
import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.CodeHighlight);

## Installation

<InstallScript packages="@mantine/code-highlight" />

After installation import package styles at the root of your application:

```tsx
import '@mantine/core/styles.css';
// ‼️ import code-highlight styles after core package styles
import '@mantine/code-highlight/styles.css';
```

## Example

`CodeHighlight` component is used to display code snippets with syntax highlighting.
It provides a flexible adapter system that allows using any code highlighting library
of your choice.

Example of code highlighting with [shiki](https://shiki.matsu.io/):

<Demo data={CodeHighlightDemos.usage} />

## Adapters

`@mantine/code-highlight` package does not depend on any specific code highlighting library.
You can choose one of the default adapters provided by the package or create your own.

Default adapters:

- `createShikiAdapter` – creates [shiki](https://shiki.matsu.io/) adapter
- `createHighlightJsAdapter` – creates [highlight.js](https://highlightjs.org/) adapter
- `plainTextAdapter` – does not highlight code, just displays it as plain text (used by default if no adapter provided)

## Usage with shiki

[Shiki](https://shiki.matsu.io/) library provides the most advanced syntax highlighting
for TypeScript and CSS/Sass code. It uses textmate grammars to highlight code (same as in VSCode).
Shiki adapter is recommended if you need to highlight advanced TypeScript (generics, jsx nested in props) or CSS code (custom syntaxes, newest features).
Shiki adapter is used for all code highlighting in Mantine documentation.

To use shiki adapter you need to install `shiki` package:

<InstallScript packages="shiki" />

Then wrap your app with `CodeHighlightAdapterProvider` and provide `createShikiAdapter` as `adapter` prop:

```tsx
import { MantineProvider } from '@mantine/core';
import { CodeHighlightAdapterProvider, createShikiAdapter } from '@mantine/code-highlight';

// Shiki requires async code to load the highlighter
async function loadShiki() {
  const { createHighlighter } = await import('shiki');
  const shiki = await createHighlighter({
    langs: ['tsx', 'scss', 'html', 'bash', 'json'],
    // You can load supported themes here
    themes: [],
  });

  return shiki;
}

const shikiAdapter = createShikiAdapter(loadShiki);

function App() {
  return (
    <MantineProvider>
      <CodeHighlightAdapterProvider adapter={shikiAdapter}>
        {/* Your app here */}
      </CodeHighlightAdapterProvider>
    </MantineProvider>
  );
}
```

After that, you can use `CodeHighlight` component in your application:

<Demo data={CodeHighlightDemos.usage} />

All further code highlighting examples on this page are using shiki adapter.

## Usage with highlight.js

[Highlight.js](https://highlightjs.org/) provides less accurate highlighting compared to shiki,
but it has smaller bundle size and better performance. Choose highlight.js adapter if you need
to highlight basic JavaScript, HTML, and CSS code.

To use highlight.js adapter you need to install `highlight.js` package:

<InstallScript packages="highlight.js" />

Then wrap your app with `CodeHighlightAdapterProvider` and provide `createHighlightJsAdapter` as `adapter` prop:

```tsx
import { MantineProvider } from '@mantine/core';
import { CodeHighlightAdapterProvider, createHighlightJsAdapter } from '@mantine/code-highlight';
import hljs from 'highlight.js/lib/core';
import tsLang from 'highlight.js/lib/languages/typescript';

hljs.registerLanguage('typescript', tsLang);

const highlightJsAdapter = createHighlightJsAdapter(hljs);

function App() {
  return (
    <MantineProvider>
      <CodeHighlightAdapterProvider adapter={highlightJsAdapter}>
        {/* Your app here */}
      </CodeHighlightAdapterProvider>
    </MantineProvider>
  );
}
```

Then you need to add styles of one of the highlight.js themes to your application.
You can do that by importing css file from `highlight.js` package or adding it via
CDN link to the head of your application:

```html
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"
/>
```

After that, you can use `CodeHighlight` component in your application.

## Create custom adapter

You can create a custom adapter if you want to enhance the default behavior of the code highlighting
or use a different library.

Example of creating a custom shiki adapter with custom themes and logic:

```tsx
import type { CodeHighlightAdapter, stripShikiCodeBlocks } from '@mantine/code-highlight';

// Shiki transformers can be used to highlight diffs and other notations
// https://shiki.style/packages/transformers
import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers'

// Shiki themes as objects, you can use any VSCode themes
import { darkTheme, lightTheme } from './shiki-themes';

async function loadShiki() {
  const { createHighlighter } = await import('shiki');
  const shiki = await createHighlighter({
    langs: ['tsx', 'scss', 'html', 'bash', 'json'],
    themes: [],
  });

  return shiki;
}

// Pass this adapter to CodeHighlightAdapterProvider component
export const customShikiAdapter: CodeHighlightAdapter = {
  // loadContext is called on client side to load shiki highlighter
  // It is required to be used if your library requires async initialization
  // The value returned from loadContext is passed to createHighlighter as ctx argument
  loadContext: loadShiki,

  // ctx is the value returned from loadContext
  // or null if loadContext is not used or has not resolved yet
  createHighlighter: (ctx) => {
    if (!ctx) {
      return ({ code }) => ({ highlightedCode: code, isHighlighted: false });
    }

    return ({ code, language, colorScheme }) => ({
      isHighlighted: true,
      // stripShikiCodeBlocks removes <pre> and <code> tags from highlighted code
      highlightedCode: stripShikiCodeBlocks(
        ctx.codeToHtml(code, {
          lang: language,
          theme: (colorScheme === 'light' ? lightTheme : darkTheme) as any,
          transformers: [transformerNotationDiff(), transformerNotationHighlight()],
        })
      ),
    });
  },
};
```

## Copy button

You can customize copy button labels with `copyLabel` and `copiedLabel` props.
In case you need to remove the copy button, set `withCopyButton={false}`.

<Demo data={CodeHighlightDemos.copy} />

## With tabs

`CodeHighlightTabs` component allows organizing multiple code blocks into tabs:

<Demo data={CodeHighlightDemos.tabs} />

## Tabs with icons

You can use any React node as tab icon. The example below uses TypeScript and CSS
icons from the `@mantinex/dev-icons` package, but you can use any other icons library or custom
icons:

<Demo data={CodeHighlightDemos.tabsIcons} />

## Tabs icons based on file name

As an alternative to providing icons manually for each tab, you can use `getFileIcon` prop
to assign icons based on file name. `getFileIcon` accepts file name and must React node
or `null`.

<Demo data={CodeHighlightDemos.tabsGetIcons} />

## Expandable code

If the code snippet is too long, you can make it expandable with `withExpandButton`
and `defaultExpanded={false}` props. To change label of the expand/collapse control
tooltip, use `expandCodeLabel` and `collapseCodeLabel`.

<Demo data={CodeHighlightDemos.expand} />

## Custom controls

Use `controls` prop with `CodeHighlightControl` component to add custom controls
to the code block:

<Demo data={CodeHighlightDemos.customControl} />

## Inline code

`InlineCodeHighlight` component allows highlighting inline code snippets:

<Demo data={CodeHighlightDemos.inline} />
